//
//  EntityManager.swift
//  GhostWorld
//
//  Created by Kam on 2018/5/2.
//  Copyright © 2018 LKGood. All rights reserved.
//

import Foundation
import Sync

private let context = CoreDataHelper.getContext()

enum CoreDataFetchType {
  case all
  case id(Int)
  case ids([Int])
}

class EntityManager {
  
  static func fetch<T: NSManagedObject>(_ type: T.Type, fetchType: CoreDataFetchType) -> [T]? {
    let entityName = String(describing: T.self)
    let request = NSFetchRequest<T>()
    request.entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
    switch fetchType {
    case .all:
      request.sortDescriptors = [NSSortDescriptor(key: "id", ascending: true)]
      break
    case .id(let id):
      request.predicate = NSPredicate(format: "id = %@", "\(id)")
    case .ids(let ids):
      request.predicate = NSPredicate(format: "id IN %@", ids)
    }
    do {
      let results = try context.fetch(request)
      return results
    } catch let error {
      loggingPrint(error)
      return nil
    }
  }
  
  //    public static let insert = OperationOptions(rawValue: 1 << 0)
  //    public static let update = OperationOptions(rawValue: 1 << 1)
  //    public static let delete = OperationOptions(rawValue: 1 << 2)
  //    public static let insertRelationships = OperationOptions(rawValue: 1 << 3)
  //    public static let updateRelationships = OperationOptions(rawValue: 1 << 4)
  //    public static let deleteRelationships = OperationOptions(rawValue: 1 << 5)
  //    public static let all: OperationOptions = [.insert, .update, .delete, .insertRelationships, .updateRelationships, .deleteRelationships]
  
  static func sync<T: NSManagedObject> (
    type: T.Type,
    rawObject: [[String: Any]],
    predicate: NSPredicate? = nil,
    operations: Sync.OperationOptions,
    completion: @escaping (NSError?, [T]?) -> Void) {
    
    let entityName = String(describing: T.self)
    CoreDataHelper.getDataStack().sync (
      rawObject,
      inEntityNamed: entityName,
      predicate: predicate,
      operations: operations,
      completion: { error in
        
        if error != nil {
          loggingPrint(error?.localizedDescription)
          completion(error, nil)
        } else {
          let ids = rawObject.map { $0["id"] as! Int }
          let results = EntityManager.fetch(type, fetchType: .ids(ids))
          completion(nil, results)
        }
    })
  }
}
